#ifndef SNC_HH
#define SNC_HH 1
//#include "list.hh"
//#include "sncpacket.hh"
#include "packetpool.hh"
#include "sncneighbor.hh"

#include <click/element.hh>
#include <click/etheraddress.hh>
#include <click/packet.hh>
#include <click/hashtable.hh>
#include <click/timer.hh>
#include <clicknet/wifi.h>

//using namespace SNCoding;
CLICK_DECLS

/*
 * =c
 * SNC
 * =s Snc
 * Simple Network Coding
 *
 * =d
 * Input 0: from device
 * Input 1: outgoing
 * Output 0: to host
 * Output 1: to device
*/

//typedef Pair<>;

#define MAXRETRY 2




//class SNCNeighborManag;

class SNC: public Element {
public:
	SNC();
	~SNC(){}

	const char *class_name() const { return "SNC"; }
	const char *port_count() const { return "2/2"; }
	const char *processing() const { return "hh/hl"; }

	 void *cast(const char *n) {
		if (strcmp(n, "SNC") == 0)
			return (SNC *) this;
		else
			return 0;
	}

	 void push(int, Packet *);
	 Packet *pull(int);

	 int configure(Vector<String> &, ErrorHandler *);


	 void add_handlers();

	 int initialize(ErrorHandler *);
	 void run_timer(Timer *);

	 EtherAddress& eth() { return _eth; }

	 static int write_param(const String &, Element *, void *vparam,
							ErrorHandler *);
private:
	 //get snc header info and strip the snc header
	 bool get_sncheader_info(Packet* p,uint8_t& type,
			 encoded_header** encoded_data,uint8_t& num1,uint8_t** code_vector,
			 report_header** report_data,uint8_t& num2,
			 ack_header** ack_data,uint8_t& num3);

	 //get the link info
	 bool get_link_credits(Packet* p){return false;}

	 //check if I am the next hop
	 bool check_next_hop(encoded_header* encoded,uint8_t num);

	 //check if there are encoding probability
	 bool check_need_decode(encoded_header* encoded,uint8_t num);

	 int32_t decode(encoded_header* encoded,uint8_t* code_vector,uint8_t num,uint8_t* data,uint16_t size);

	 WritablePacket * prepare_encoded_pkt(Packet* p);

	 //void encode(Natives& natives,Packet * p);

	 //update own pktpool
	 void update_pktpool(uint32_t src_ip,uint16_t seqno,const uint8_t* data,uint32_t size);

	 //periodicity check if there are acks or reports waitting to be sent
	 void check_padding();

	 uint32_t calc_DATA_size(Natives& natives);

	 uint32_t calc_sncheader_size(Natives& natives);

	 //add ack to the ack queue
	 void pad_ack(const uint8_t* mac,uint16_t seqno);

	 void pad_report(const uint32_t src_ip,uint16_t seqno);

	 uint32_t make_encode_header(Natives& natives,uint8_t* data);

	 uint32_t make_report_header(uint8_t* data);

	 uint32_t make_ack_header(uint8_t* data);

	 void sncheader_encap(Packet *p);

	 bool get_wifi_info(Packet* p,EtherAddress& bssid,EtherAddress& src,EtherAddress& dst,click_wifi& wifi);

	 void clear_pktpool();
protected:

	 EtherAddress _eth;  //self mac
	 unsigned _max;
	 Vector<ack > _padding_ack;
	 Vector<report > _padding_report;
	 unsigned _poolcap;
	 unsigned _sendqcap;
	 unsigned _pkt_threshold;
	 unsigned _retry;
	 unsigned _period;
	 PacketPool _pktpool;
	 Packet_list _sendq;  //store ether packet
	 Packet_list _sncencapedq;
	 SNCNeighborManag _neighbor_manag;
	 Timer _timer;
	 bool _router;

	 friend class SNCNeighborManag;
};



CLICK_ENDDECLS

#endif
